package javango.contrib.hibernate;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.Order;

import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;

import javango.db.ManagerException;
import javango.db.QuerySet;

public class HibernateQuerySet<T> implements QuerySet<T> {

	Criteria criteria;
	
	HibernateUtil hibernateUtil;
	ModelDaoHelper daoHelper;
	
	@AssistedInject
	public HibernateQuerySet(HibernateUtil hibernateUtil,
			ModelDaoHelper daoHelper, @Assisted Class clazz) throws ManagerException {
		super();
		this.hibernateUtil = hibernateUtil;
		this.daoHelper = daoHelper;
		try {
		criteria = hibernateUtil.getSession().createCriteria(clazz);
		} catch (DaoException e) {
			throw new ManagerException(e);
		}
	}

	public long count() throws ManagerException {
		try {
		return new Long(hibernateUtil.doCount(criteria));
		} catch (DaoException e) {
			throw new ManagerException(e);
		}
	}

	public QuerySet<T> filter(Object params) throws ManagerException {
		try {
		daoHelper.updateCriteria(criteria, params);
		} catch (DaoException e) {
			throw new ManagerException(e);
		}
		return this;
	}

	public QuerySet<T> filter(String property, Object value) throws ManagerException {
		try {
		daoHelper.processField(criteria, property, value, null, null);
		} catch (DaoException e) {
			throw new ManagerException(e);
		}
		return this;
	}

	public QuerySet<T> limit(int arg0, int arg1) throws ManagerException {
		criteria.setFirstResult(arg0 < 1 ? 0 : arg0 - 1);
		criteria.setMaxResults(arg1 >= arg0 ? arg1-arg0+1 : 0);
		return this;
	}
	
	public T get() throws ManagerException {
		try {
			return (T)criteria.uniqueResult();
		} catch (HibernateException e) {
			throw new ManagerException(e);
		}
	}

	public List<T> list() throws ManagerException {
		return criteria.list();
	}
	
	public Iterator<T> iterator() {
		try {
			return list().iterator();
		} catch (ManagerException e) {
			// TODO What to do with this exception
			throw new RuntimeException(e);
		}
	}

	public QuerySet<T> orderBy(String... arg0) {
		for (String s : arg0) {
			if (s.startsWith("-")) {
				criteria.addOrder(Order.desc(s.substring(1)));
			} else {
				criteria.addOrder(Order.asc(s));
			}
		}
		return this;
	}

	public org.hibernate.Criteria getCirteria() {
		return criteria;
	}

	public void setCirteria(org.hibernate.Criteria cirteria) {
		this.criteria = cirteria;
	}

}
